package com.ylsk.flowable.service.impl;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.ylsk.common.constant.ActivitiConstants;
import com.ylsk.common.core.domain.AjaxResult;
import com.ylsk.common.enums.OperateTypeEnum;
import com.ylsk.common.utils.ActivitiUtils;
import com.ylsk.flowable.domain.vo.Attachment;
import com.ylsk.flowable.domain.vo.Page;
import com.ylsk.flowable.service.IWorkFlowService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfoQuery;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Description 流程运行和历史服务接口实现类
 * version V1.0
 */
@Service
@Slf4j
public class WorkFlowServiceImpl implements IWorkFlowService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WorkFlowServiceImpl.class.getSimpleName());

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Override
    public AjaxResult supendProcessInstanceByTaskId(String taskId) {
        if (Strings.isNullOrEmpty(taskId)) {
            return AjaxResult.error("任务id不能为空");
        }
        long activeCount = taskService.createTaskQuery().active().taskId(taskId).count();
        if (activeCount > 0) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            runtimeService.suspendProcessInstanceById(task.getProcessInstanceId());
            return AjaxResult.success();
        }
        return AjaxResult.error("挂起流程实例失败");
    }

    @Override
    public AjaxResult activateProcessInstanceByTaskId(String taskId) {
        if (Strings.isNullOrEmpty(taskId)) {
            return AjaxResult.error("任务id不能为空");
        }
        long suspendCount = taskService.createTaskQuery().suspended().taskId(taskId).count();
        if (suspendCount > 0) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            runtimeService.activateProcessInstanceById(task.getProcessInstanceId());
            return AjaxResult.success();
        }
        return AjaxResult.error("激活流程实例失败");
    }

    @Override
    public AjaxResult supendProcessInstanceByBusinessId(String businessId) {
        if (Strings.isNullOrEmpty(businessId)) {
            return AjaxResult.error("业务id不能为空");
        }
        long activeCount = runtimeService.createProcessInstanceQuery().active().processInstanceBusinessKey(businessId).count();
        if (activeCount > 0) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().active().processInstanceBusinessKey(businessId).singleResult();
            runtimeService.suspendProcessInstanceById(processInstance.getId());
            return AjaxResult.success();
        }
        return AjaxResult.error("挂起流程实例失败");
    }

    @Override
    public AjaxResult activateProcessInstanceByBusinessId(String businessId) {
        if (Strings.isNullOrEmpty(businessId)) {
            return AjaxResult.error("业务id不能为空");
        }
        long supendCount = runtimeService.createProcessInstanceQuery().suspended().processInstanceBusinessKey(businessId).count();
        if (supendCount > 0) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().suspended().processInstanceBusinessKey(businessId).singleResult();
            runtimeService.activateProcessInstanceById(processInstance.getId());
            return AjaxResult.success();
        }
        return AjaxResult.error("激活流程实例失败");
    }

    @Override
    public AjaxResult listTodoTasksByPage(String userId, Page page) {
        return AjaxResult.success();
    }

    @Override
    public AjaxResult listDoneTaskByPage(String userId, Page page) {
        return null;
    }

    @Override
    public AjaxResult listRunningProcessinstance(String userId, Page page, String type) {
        return null;
    }

    @Override
    public AjaxResult listHistoricTaskInstance(String processInstanceId, String type) {
        return null;
    }

    @Override
    public AjaxResult startProcessInstanceByKey(String key, String businessId, Map<String, Object> params, Object businessObj, String userId) throws Exception {
        try {
            if (Strings.isNullOrEmpty(key)) {
                AjaxResult.error("流程key不能为空");
            }
            if (Strings.isNullOrEmpty(businessId)) {
                AjaxResult.error("业务id不能为空");
            }
            if (Strings.isNullOrEmpty(userId)) {
                AjaxResult.error("用户id不能为空");
            }
            identityService.setAuthenticatedUserId(userId);
            Map<String, Object> businessParams = Maps.newHashMap();
            ActivitiUtils.business2Variable(businessParams, businessObj);

            businessParams.put("businessId", businessId);
            businessParams.put("employeeId", userId);
            ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder().businessKey(businessId).processDefinitionKey(key)
                    .variables(businessParams).transientVariables(params).start();
            identityService.setAuthenticatedUserId(null);
            if (processInstance != null) {
                return AjaxResult.success(processInstance.getProcessInstanceId());
            } else {
                throw new RuntimeException("启动流程失败");
            }
        } catch (Exception e) {
            throw new RuntimeException("启动流程失败", e);
        }
    }

    @Override
    public AjaxResult startProcessInstanceById(String id, String businessId, Map<String, Object> params, Object businessObj, String userId) throws Exception {
        try {
            if (Strings.isNullOrEmpty(id)) {
                AjaxResult.error("流程id不能为空");
            }
            if (Strings.isNullOrEmpty(businessId)) {
                AjaxResult.error("业务id不能为空");
            }
            if (Strings.isNullOrEmpty(userId)) {
                AjaxResult.error("用户id不能为空");
            }
            Map<String, Object> businessParams = Maps.newHashMap();
            businessParams.put("businessId", businessId);
            businessParams.put("assignee",userId);
            ActivitiUtils.business2Variable(businessParams, businessObj);
            identityService.setAuthenticatedUserId(userId);

            ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder().businessKey(businessId).processDefinitionId(id)
                    .variables(businessParams).transientVariables(params).start();
            identityService.setAuthenticatedUserId(null);

            if (processInstance != null) {
                return AjaxResult.success("操作成功",processInstance.getProcessInstanceId());
            } else {
                throw new RuntimeException("启动流程失败");
            }

        } catch (Exception e) {
            throw new RuntimeException("启动流程失败", e);
        }
    }

    @Override
    public AjaxResult listPartakeByPage(String userId, Page page, String type) {
        return null;
    }

    @Override
    public AjaxResult completeTask(String taskId, Map<String, Object> params, String commet, List<Attachment> attachements, Object businessObj, String userId, OperateTypeEnum operateTypeEnum) throws Exception {
        {
            try {
                if (Strings.isNullOrEmpty(taskId)) {
                    AjaxResult.error("任务id不能为空");
                }
                if (Strings.isNullOrEmpty(userId)) {
                    AjaxResult.error("用户id不能为空");
                }
                Task task = taskService.createTaskQuery().taskId(taskId).taskCandidateOrAssigned(userId).singleResult();
                if (task == null) {
                    LOGGER.info("此用户{}没有{}任务", userId, taskId);
                    throw new RuntimeException(String.format("用户%s没有%s任务", userId, taskId));
                } else {
                    if (Strings.isNullOrEmpty(task.getAssignee())) {
                        taskService.claim(taskId, userId);
                    } else {
                        taskService.claim(taskId, task.getAssignee());
                    }
                    //带批注
                    StringBuffer commetBuffer = new StringBuffer();
                    params = params == null ? new HashMap<>() : params;
                    if (OperateTypeEnum.AGREE == operateTypeEnum) {
                        commet = Strings.isNullOrEmpty(commet) ? "同意" : commet;
                        commetBuffer.append(OperateTypeEnum.AGREE.getCode()).append(ActivitiConstants.COMMET_SEPARATOR).append(commet);
                        params.put(ActivitiConstants.OPREATE_TYPE, OperateTypeEnum.AGREE.getCode());
                    } else {
                        commet = Strings.isNullOrEmpty(commet) ? "驳回" : commet;
                        commetBuffer.append(OperateTypeEnum.REJECT.getCode()).append(ActivitiConstants.COMMET_SEPARATOR).append(commet);
                        params.put(ActivitiConstants.OPREATE_TYPE, OperateTypeEnum.REJECT.getCode());
                    }
                    taskService.addComment(taskId, task.getProcessInstanceId(), commetBuffer.toString());
                    //带附件
                    addAttachment(attachements, task, "approval");
                    //业务对象
                    Map<String, Object> businessParams = Maps.newHashMap();
                    ActivitiUtils.business2Variable(businessParams, businessObj);

                    taskService.complete(taskId, businessParams, params);
                    return AjaxResult.success();
                }
            } catch (Exception e) {
                throw new RuntimeException("完成任务失败", e);
            }

        }
    }

    @Override
    public AjaxResult batchCompleteTask(List<String> taskIds, Map<String, Object> params, String commet, String userId) throws Exception {
        return null;
    }

    @Override
    public AjaxResult completeDelegateTask(String taskId, Map<String, Object> params, String commet, List<Attachment> attachements, String userId) {
        return null;
    }

    @Override
    public AjaxResult jumpAndCompleteTask(String taskId, Map<String, Object> params, String commet, String desActivityId, boolean toStartActivity, List<Attachment> attachements, String userId) {
        return null;
    }

    @Override
    public AjaxResult delegateTask(String taskId, String delegateUserId) throws Exception {
        return null;
    }

    @Override
    public AjaxResult stopProcessInstance(String taskId, String reson) throws Exception {
        return null;
    }

    @Override
    public AjaxResult stopProcessInstanceByProcessInstanceId(String processInstanceID, String reson) throws Exception {
        return null;
    }

    @Override
    public AjaxResult queryTodoTaskCount(String userId) {
        return null;
    }

    @Override
    public AjaxResult getTaskByUserIdAndProcessInstanceId(String userId, String processInstanceId) {
        return null;
    }

    @Override
    public AjaxResult updateVariableForProcessInstance(String processInstanceId, Object varObj) {
        return null;
    }

    @Override
    public AjaxResult listTodoTaskCountOfTaskNodeWithProcessDefinition(String processDefinitionId, String userId) {
        return null;
    }

    @Override
    public AjaxResult getTodoTaskCount(String userId) {
        return null;
    }

    @Override
    public AjaxResult getFinishedTaskByInstanceId(Set<String> instanceIdSet) {
        return null;
    }

    @Override
    public AjaxResult sendMsgToPushNode(String msg, String instanceId) throws Exception {
        return null;
    }

    @Override
    public AjaxResult listTodoTasksByPIdsAndUserId(List<String> processInstanceIds, String userId) {
        return null;
    }

    @Override
    public AjaxResult moveCurrentTaskToReApplyActId(String taskId, String destActId, String commet, Map<String, Object> params, String userId) {
        return null;
    }

    @Override
    public AjaxResult getUserTaskByBusinessId(String businessId) {
        return null;
    }


    /***
     * @methodname addAttachment
     * @Description 添加审批附件
     * @author zjh
     * @create 2018/8/17 0017 下午 1:56
     * @param attachements 附件集合
     *@param  task 任务对象
     *@param  attachemntType 附件类型
     * @throws
     * @return void
     */

    private void addAttachment(List<Attachment> attachements, Task task, String attachemntType) {
        if (CollectionUtils.isNotEmpty(attachements)) {
            for (Attachment attachment : attachements) {
                //附件存放的是字节流
                if (Strings.isNullOrEmpty(attachment.getUrl())) {
                    if (ArrayUtils.isNotEmpty(attachment.getBytes())) {
                        taskService.createAttachment(attachemntType, task.getId(), task.getProcessInstanceId(), attachment.getName(),
                                attachment.getDesc(), new ByteArrayInputStream(attachment.getBytes()));
                    }
                } else { //附件存放的是路径
                    taskService.createAttachment(attachemntType, task.getId(), task.getProcessInstanceId(), attachment.getName(),
                            attachment.getDesc(), attachment.getUrl());
                }

            }
        }
    }
}
